package com.example.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.client.hospital.HospitalFeignClient;
import com.example.client.user.PatientFeignClient;
import com.example.common.rabbit.service.RabbitService;
import com.example.common.util.constant.CommonUtilConstants;
import com.example.common.util.constant.Constants;
import com.example.common.util.constant.OrderConstants;
import com.example.common.util.enums.BusinessEnum;
import com.example.common.util.enums.OrderStatusEnums;
import com.example.common.util.exception.BusinessException;
import com.example.common.util.utils.DateUtils;
import com.example.common.util.utils.StringUtils;
import com.example.model.vo.hospital.ScheduleOrderVo;
import com.example.model.domain.entity.order.OrderInfo;
import com.example.model.domain.entity.user.Patient;
import com.example.model.vo.order.*;
import com.example.model.vo.sms.SmsVo;
import com.example.order.mapper.OrderInfoMapper;
import com.example.order.service.OrderInfoService;
import com.example.order.service.WeiXinPayService;
import com.example.service.util.HttpRequestHelper;
import com.example.service.util.conversion.FeignResultConversion;
import com.example.service.util.conversion.OrderInfoConversion;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author juzipi
 * @Date 2021/7/23 21:02
 * @Info
 */
@Service
public class OrderInfoServiceImpl implements OrderInfoService {


    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private PatientFeignClient patientFeignClient;

    @Autowired
    private HospitalFeignClient hospitalFeignClient;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private WeiXinPayService weiXinPayService;


    /**

     * 查询订单
     *
     * @param orderId 订单ID
     * @return 订单
     */
    @Override
    public OrderInfo selectOrderInfoById(Long orderId)
    {
        return orderInfoMapper.selectOrderInfoById(orderId);
    }

    /**


    /**

     * 新增订单
     *
     * @param orderInfo 订单
     * @return 结果
     */
    @Override
    public int insertOrderInfo(OrderInfo orderInfo)
    {
        orderInfo.setCreateTime(DateUtils.getNowDate());
        return orderInfoMapper.insertOrderInfo(orderInfo);
    }

    /**

     * 修改订单
     *
     * @param orderInfo 订单
     * @return 结果
     */
    @Override
    public int updateOrderInfo(OrderInfo orderInfo)
    {
        orderInfo.setUpdateTime(DateUtils.getNowDate());
        return orderInfoMapper.updateOrderInfo(orderInfo);
    }

    /**

     * 批量删除订单
     *
     * @param ids 需要删除的订单ID
     * @return 结果
     */
    @Override
    public int deleteOrderInfoByIds(Long[] ids)
    {
        return orderInfoMapper.deleteOrderInfoByIds(ids);
    }


    @Override
    public Long saveOrders(String hosScheduleId, Long patientId) {
        //远程调用接口，获取就诊人信息
        Object patientObject = patientFeignClient.getPatient(patientId).get(Constants.DATA);
        Patient patient = FeignResultConversion.convertResult(patientObject, Patient.class);
        System.out.println(patient.getCityCode());
        //获取排班信息
        Object scheduleOrderVoObject = hospitalFeignClient.getScheduleOrderVo(hosScheduleId).get(Constants.DATA);
        ScheduleOrderVo scheduleOrderVo = FeignResultConversion.convertResult(scheduleOrderVoObject, ScheduleOrderVo.class);
        if (DateUtils.isAfterNow(scheduleOrderVo.getStartTime()) || DateUtils.isBeforeNow(scheduleOrderVo.getEndTime())){
            throw new BusinessException(BusinessEnum.NOW_NOT_RESERVE);
        }
        //获取签名信息
        Object signInfoVoObject = hospitalFeignClient.getHospitalSignByHoscode(scheduleOrderVo.getHoscode()).get(Constants.DATA);
        SignInfoVo signInfoVo = FeignResultConversion.convertResult(signInfoVoObject, SignInfoVo.class);
        //添加到订单
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(scheduleOrderVo,orderInfo);
        //对外贸易号？
        String outTradeNo = System.currentTimeMillis() + "-" + new Random().nextInt(100);
        orderInfo.setOutTradeNo(outTradeNo);
        orderInfo.setHosScheduleId(hosScheduleId);
        orderInfo.setUserId(patient.getUserId());
        orderInfo.setPatientId(patientId);
        orderInfo.setPatientName(patient.getName());
        orderInfo.setPatientPhone(patient.getPhone());
        orderInfo.setOrderStatus(OrderConstants.UNPAID);
        orderInfoMapper.insertOrderInfo(orderInfo);
        //设置医院接口需要的参数，map集合
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put(OrderConstants.HOSCODE,orderInfo.getHoscode());
        hashMap.put(OrderConstants.DEPCODE,orderInfo.getDepcode());
        hashMap.put(OrderConstants.HOS_SCHEDULE_ID,orderInfo.getHosScheduleId());
        String date = DateUtils.formatDateToYMD(orderInfo.getReserveDate());
        hashMap.put(OrderConstants.RESERVE_DATE,date);
        hashMap.put(OrderConstants.RESERVE_TIME,orderInfo.getReserveTime());
        hashMap.put(OrderConstants.AMOUNT,orderInfo.getAmount());

        hashMap.put(OrderConstants.NAME,patient.getName());
        hashMap.put(OrderConstants.CERTIFICATES_TYPE,patient.getCertificatesType());
        hashMap.put(OrderConstants.CERTIFICATES_NO,patient.getCertificatesNo());
        hashMap.put(OrderConstants.SEX,patient.getSex());
        hashMap.put(OrderConstants.BIRTHDATE,patient.getBirthdate());
        hashMap.put(OrderConstants.PHONE,patient.getPhone());
        hashMap.put(OrderConstants.IS_MARRY,patient.getIsMarry());
        hashMap.put(OrderConstants.PROVINCE_CODE,patient.getProvinceCode());
        hashMap.put(OrderConstants.CITY_CODE,patient.getCityCode());
        hashMap.put(OrderConstants.DISTRICT_CODE,patient.getDistrictCode());
        hashMap.put(OrderConstants.ADDRESS,patient.getAddress());
        //联系人相关
        hashMap.put(OrderConstants.CONTACTS_NAME,patient.getContactsName());
        hashMap.put(OrderConstants.CONTACTS_CERTIFICATES_TYPE,patient.getContactsCertificatesType());
        hashMap.put(OrderConstants.CONTACTS_CERTIFICATES_NO,patient.getContactsCertificatesNo());
        hashMap.put(OrderConstants.CONTACTS_PHONE,patient.getContactsPhone());
        hashMap.put(OrderConstants.TIMESTAMP, HttpRequestHelper.getTimestamp());
        String sign = HttpRequestHelper.getSign(hashMap, signInfoVo.getSignKey());
        hashMap.put(OrderConstants.SIGN,sign);
        //请求医院系统接口
        JSONObject result = HttpRequestHelper.sendRequest(hashMap, signInfoVo.getApiUrl() + "order/submitOrder");
        if (result.getInteger(Constants.CODE)==200){
            JSONObject jsonObject = result.getJSONObject(Constants.DATA);
            //预约记录主键
            String hosRecordId = jsonObject.getString(OrderConstants.HOS_RECORD_ID);
            //预约序号
            Integer number = jsonObject.getInteger(OrderConstants.NUMBER);
            //取号时间
            String fetchTime = jsonObject.getString(OrderConstants.FETCH_TIME);
            //取号地址
            String fetchAdress = jsonObject.getString(OrderConstants.FETCH_ADDRESS);
            //更新订单
            orderInfo.setHosRecordId(hosRecordId);
            orderInfo.setNumber(number);
            orderInfo.setFetchTime(fetchTime);
            orderInfo.setFetchAddress(fetchAdress);
            orderInfoMapper.updateOrderInfo(orderInfo);
            //排班可预约数
            Integer reservedNumber = jsonObject.getInteger(OrderConstants.RESERVED_NUMBER);
            //排班剩余预约数
            Integer availableNumber = jsonObject.getInteger(OrderConstants.AVAILABLE_NUMBER);
            //发送mq消息，号源更新和短信通知
            OrderMqVo orderMqVo = new OrderMqVo();
            orderMqVo.setScheduleId(hosScheduleId);
            orderMqVo.setReservedNumber(reservedNumber);
            orderMqVo.setAvailableNumber(availableNumber);

            SmsVo smsVo = new SmsVo();
            smsVo.setPhone(orderInfo.getPatientPhone());
            smsVo.setTemplateCode("2");//2为下单成功预约更新邮件
            String dateToYMD = DateUtils.formatDateToYMD(orderInfo.getReserveDate());
            String reserveDate = dateToYMD+(orderInfo.getReserveTime() == 0 ? "上午":"下午");
            HashMap<String, Object> param = new HashMap<>(){{
                put(OrderConstants.TITLE,orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());
                put(OrderConstants.AMOUNT,orderInfo.getAmount());//订单数量？
                put(OrderConstants.RESERVE_DATE,reserveDate);
                put(OrderConstants.NAME,orderInfo.getPatientName());
                String dateToYMDHM = DateUtils.formatDateToYMDHM(orderInfo.getQuitTime());
                put(OrderConstants.QUIT_TIME,dateToYMDHM);//退出时间？
            }};
            smsVo.setParam(param);
            orderMqVo.setSmsVo(smsVo);
            //发送信息,order交换机和路由
            Boolean aBoolean = rabbitService.sendMessage(CommonUtilConstants.ORDER_EXCHANGE, CommonUtilConstants.ORDER_ROUTING, orderMqVo);
        }else {
            throw new BusinessException(BusinessEnum.OPTION_ERROR);
        }
        return orderInfo.getId();
    }



    @Override
    public PageInfo<OrderInfo> getOrderInfoPage(Integer pageNum, Integer pageSize, OrderQueryVo orderQueryVo) {
//        String name = orderQueryVo.getKeyword();//医院名称
//        String patientName = orderQueryVo.getPatientName();//就诊人名称
//        String orderStatus = orderQueryVo.getOrderStatus();//订单状态
//        String reserveDate = orderQueryVo.getReserveDate();//安排时间
//        String createTimeBegin = orderQueryVo.getCreateTimeBegin();
//        String createTimeEnd = orderQueryVo.getCreateTimeEnd();
        PageHelper.startPage(pageNum,pageSize);
        List<OrderInfo> orderInfos = orderInfoMapper.selectOrderInfoPage(orderQueryVo);
        PageInfo<OrderInfo> orderInfoPageInfo = new PageInfo<>(orderInfos);
        List<OrderInfo> orderInfoList = orderInfoPageInfo.getList();
        orderInfoList.forEach(this::patchOrderInfo);
        return orderInfoPageInfo;
    }



    @Override
    public Boolean cancelOrderById(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectOrderInfoById(orderId);
        Date quitTime = orderInfo.getQuitTime();
        //判断是否可以取消
        if (DateUtils.isAfterNow(quitTime)){
            Object signInfoVoObject = hospitalFeignClient.getHospitalSignByHoscode(orderInfo.getHoscode()).get(Constants.DATA);
            SignInfoVo signInfoVo = FeignResultConversion.convertResult(signInfoVoObject, SignInfoVo.class);
            if (StringUtils.isNotNull(signInfoVo)){
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put(OrderConstants.HOSCODE,orderInfo.getHoscode());
                hashMap.put(OrderConstants.HOS_RECORD_ID,orderInfo.getHosRecordId());
                hashMap.put(OrderConstants.TIMESTAMP,HttpRequestHelper.getTimestamp());
                hashMap.put(OrderConstants.SIGN,HttpRequestHelper.getSign(hashMap,signInfoVo.getSignKey()));
                JSONObject result = HttpRequestHelper.sendRequest(hashMap, signInfoVo.getApiUrl() + "order/updateCancelStatus");
                if (result.getInteger(Constants.CODE) == 200){
                    //是否已支付退款
                    if (orderInfo.getOrderStatus().intValue() == OrderConstants.PAID){
                        if (weiXinPayService.refund(orderId)) {
                            //更新订单状态
                            orderInfo.setOrderStatus(OrderConstants.CANCEL_RESERVE);
                            orderInfoMapper.updateOrderInfo(orderInfo);
                            //发送mq信息更新预约数，与下单成功更新预约数使用相同的mq信息
                            //不设置可预约数与剩余预约数，接收端可预约数-1
                            OrderMqVo orderMqVo = new OrderMqVo();
                            orderMqVo.setScheduleId(orderInfo.getHosScheduleId());
                            //短信
                            SmsVo smsVo = new SmsVo();
                            smsVo.setPhone(orderInfo.getPatientPhone());
                            smsVo.setTemplateCode("1");//1为预约更新邮件
                            String reserveDate = DateUtils.formatDateToYMD(orderInfo.getReserveDate()) + (orderInfo.getReserveTime() == 0 ? "上午" : "下午");
                            HashMap<String, Object> param = new HashMap<>(){{
                               put(OrderConstants.TITLE,orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());
                               put(OrderConstants.RESERVE_DATE,reserveDate);
                               put(OrderConstants.NAME,orderInfo.getPatientName());
                            }};
                            smsVo.setParam(param);
                            orderMqVo.setSmsVo(smsVo);
                            //发送的是order队列
                            rabbitService.sendEmail(CommonUtilConstants.ORDER_EXCHANGE,CommonUtilConstants.ORDER_ROUTING,orderMqVo);
                        }
                        throw new BusinessException(BusinessEnum.CANCEL_ORDER_ERROR);
                    }
                    return true;
                }
                throw new BusinessException(BusinessEnum.OPTION_ERROR);
            }
            throw new BusinessException(BusinessEnum.PARAM_ERROR);
        }
        throw new BusinessException(BusinessEnum.CANCEL_ORDER_CAN_NOT);
    }

    @Override
    public Map<String, Object> getOrderInfoCountMap(OrderCountQueryVo orderCountQueryVo) {
        List<OrderCountVo> orderCountVos = orderInfoMapper.selectOrderInfoCount(orderCountQueryVo);
        //获取x轴需要的日期数据，list集合
        List<String> dateList = orderCountVos.stream().map(OrderCountVo::getReserveDate).collect(Collectors.toList());
        //获取y轴需要的具体数量
        List<Integer> countList = orderCountVos.stream().map(OrderCountVo::getCount).collect(Collectors.toList());
        HashMap<String, Object> map = new HashMap<>();
        map.put(OrderConstants.DATE_LIST,dateList);
        map.put(OrderConstants.COUNT_LIST,countList);
        return map;
    }


    @Override
    public Map<String,Object> getOrderInfoMap(Long orderId) {
        HashMap<String, Object> hashMap = new HashMap<>();
        OrderInfo orderInfo = this.patchOrderInfo(orderInfoMapper.selectOrderInfoById(orderId));
        hashMap.put(OrderConstants.ORDER_INFO,orderInfo);
        Object patientObject = patientFeignClient.getPatient(orderInfo.getPatientId()).get(Constants.DATA);
        Patient patient = FeignResultConversion.convertResult(patientObject, Patient.class);
        hashMap.put(OrderConstants.PATIENT,patient);
        return hashMap;
    }


    @Override
    public OrderInfo getOrderInfoById(Long orderId) {
        return orderInfoMapper.selectOrderInfoById(orderId);
    }


    @Override
    public Boolean remindPatient() {
        //第一个参数为等于,第二个参数是非等于
        List<OrderInfo> orderInfos = orderInfoMapper.selectListByReserveDateAndNEOrderStatus(DateUtils.getDate(), OrderStatusEnums.CANCEL_RESERVE.getStatus());
        orderInfos.forEach(orderInfo -> {
            SmsVo smsVo = new SmsVo();
            smsVo.setPhone(orderInfo.getPatientPhone());
            smsVo.setTemplateCode("0");//0代表通知就诊人邮件
            String dateToYMD = DateUtils.formatDateToYMD(orderInfo.getReserveDate());
            String reserveDate = dateToYMD +(orderInfo.getReserveTime() == 0 ? "上午":"下午");
            HashMap<String, Object> hashMap = new HashMap<>(){{
                put(OrderConstants.TITLE,orderInfo.getHosname()+"|"+orderInfo.getDepname()+"|"+orderInfo.getTitle());//标题
                put(OrderConstants.RESERVE_DATE,reserveDate);//预约日期
                put(OrderConstants.NAME,orderInfo.getPatientName());//名字
            }};
            /*
            这里是：首先定时任务发送了一条mq消息，消息消费后执行此方法，然而此方法也是发送一条mq消息
             */
            smsVo.setParam(hashMap);
            rabbitService.sendEmail(CommonUtilConstants.MAIL_EXCHANGE,CommonUtilConstants.MAIL_ROUTING,smsVo);
        });
        return true;
    }


    /**
     * orderInfo status转String
     * @param orderInfo
     * @return
     */
    private OrderInfo patchOrderInfo(OrderInfo orderInfo) {
        orderInfo.getParam().put(OrderConstants.ORDER_STATUS_STRING, OrderInfoConversion.stateTransition(orderInfo.getOrderStatus()));
        return orderInfo;
    }

}
